
/**
 * Copyright (C) 2005 WUZEWEN. All rights reserved.
 * WUZEWEN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package com.kingcore.director.setting.bean;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import org.apache.log4j.Logger;

import com.kingcore.director.DirectorConstants;
import com.kingcore.framework.context.ApplicationContext;

/**  archive
 * <p>计算级系统资料备份程序.
 * 		2006-05-19 修改为从数据库获取备份路径而不是properties文件。</p>
 * @author	WUZEWEN on 2005-10-16
 * @version	1.0
 * @see		Object#equals(java.lang.Object)
 * @see		Object#hashCode()
 * @see		HashMap
 * @since	JDK5
 */

public class FilesBackupBean implements Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	//备份方法：在指定的时间间隔做完全备份，其他时间做增量备份
	private String lastBackup="";				//上次备份总路径
	private int backupType=2;					//备份类型，默认为2
	public static int FILEBACKUPTYPE_FULL=1;	//1：完全备份
	public static int FILEBACKUPTYPE_INCREASE=2;//2：增量备份
	private static String configPath="conf/";			//2：备份配置路径
	protected Logger log=Logger.getLogger(FilesBackupBean.class);

	/**
	 * Constructor Method FilesBackupBean
	 *
	 *
	 */
	public FilesBackupBean() {
		//AA aa=new AA();
		//aa.test();
	}
	
	public static void setConfigPath(String path){
		configPath=path;
	}
	public static String getConfigPath(){
		return configPath;
	}

	/**
	 * Method main
	 * String[] args = new String[]{"-destPath"+destPath, "-backupSort"+backupSort};
	 * @param args 运行参数,such as: -destPathD:/Tmp -backupSortA9
	 *
	 */
	public static void main(String[] args) throws Exception {
		String destPath = null;
		String backupSort = null;
		if (args!=null) {
			for (String arg : args) {
				if (arg!=null && arg.startsWith("-destPath")) {
					destPath = arg.substring( "-destPath".length() );
				}
				if (arg!=null && arg.startsWith("-backupSort")) {
					backupSort = arg.substring( "-backupSort".length() );
				}
			}
		}
		executeBackup(destPath, backupSort, null);
	}
	
	public static void executeBackup(String destPath, String backupSort, List<String> fileUriList) throws Exception {
		
		Logger log=Logger.getLogger(FilesBackupBean.class);
		java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH");
		//Date toDay=new java.util.Date();

		//获取配置文件值 
		//String srcPath0=null;		//is never read.
		String strInterval=null;
		String diskNeeded=null;	//是否需要盘符，对于移动盘考到硬盘，不需要盘符D:/E:/F:...
		int beginPos;
		
		int interval;
		String lastBackup="";
		String destBackup="";	//指定的备份目标路径，而不是按照日期生成yyyy-mm-dd_I。

		String sql="";
		Connection conn=null;
		Statement stmt=null;
		ResultSet rs=null;
		try
		{		
			//log.debug(new java.io.File("").getAbsolutePath());
			//下面的方法可以像log4j一样打包。不要再试了，没有必要性。

			//log.debug("fffffff");
			//pro.load( FilesBackupBean.class.getResourceAsStream("properties_2005_filesbackup.properties"));
//			log.debug("fffffff");
//			InputStream is = FilesBackupBean.class.getResourceAsStream("properties_2005_filesbackup.properties");
//			log.debug("f-----2");		      
//			ClassLoader cld=FilesBackupBean.class.getClassLoader();
//			log.debug("f-----2--1");
//			is=cld.getResourceAsStream("properties_2005_filesbackup.properties");
//			
//			pro.load(is);
//			log.debug("f----3");

			//System.out.println(FilesBackupBean.getConfigPath()+"filesbackup.properties");
//			pro.load(new java.io.FileInputStream(FilesBackupBean.getConfigPath()+"filesbackup.properties"));
			//获取prefix信息
//			conf_prefix=pro.getProperty("user-config");

			conn= ApplicationContext.getInstance().getDataSourceManager().getConnection();
			stmt = conn.createStatement();
			if (backupSort==null) {
				sql = "Select Val From SYS_Setting Where Key='"+DirectorConstants.File_Backup_CurrentSort+"'";
				rs = stmt.executeQuery(sql);
				if(rs.next()){
					backupSort= rs.getString("Val");
				} else {
					backupSort="A1";
				}
			}
			log.debug ("using backupSort="+backupSort);
			System.out.println("destPath="+destPath + "  backupSort="+backupSort );
			
			String ts_time = null;
			rs=stmt.executeQuery("SELECT val from "+DirectorConstants.SYS_Setting+" WHERE KEY='"+DirectorConstants.File_Backup_Time+"'");
			if(rs.next()){
				ts_time=rs.getString("val");
			}
			Date bakDay=new Date();
			if (ts_time!=null) {
				sdf.applyPattern("yyyy-MM-dd");
				String strToday=sdf.format(new java.util.Date());
				strToday=strToday+" "+ts_time.trim()+":00";
				sdf.applyPattern("yyyy-MM-dd HH:mm:ss");
				bakDay=sdf.parse(strToday);
			}
			
//			conf_prefix+=".";
//			destPath=pro.getProperty(conf_prefix+"destPath");	//目标路径
//			//srcPath0=pro.getProperty(conf_prefix+"srcPath0");	//源路径
//			strInterval=pro.getProperty(conf_prefix+"interval");	//完全备份的时间间隔
//			lastBackup =pro.getProperty(conf_prefix+"lastBackup");	//上次全备路径
//			destBackup =pro.getProperty(conf_prefix+"destBackup");	//本次路径
//			diskNeeded =pro.getProperty(conf_prefix+"diskNeeded");	//是否需要盘符
//			String strPos=pro.getProperty(conf_prefix+"beginPos");
//			beginPos=0;


//			destPath=pro.getProperty(conf_prefix+"destPath");	//目标路径，以这里为准。而不是 userdata.path.

			if (destPath==null) {  //如果没有传递就从数据库取
				sql = "Select Val From SYS_Setting Where Key='"+DirectorConstants.File_Backup_DestPath+"'";
				rs = stmt.executeQuery(sql);
				if(rs.next()){
					destPath= rs.getString("Val");
				} else {
					throw new Exception("数据库中没有备份目标路径数据！");
				}	
			}
			log.debug ("using destPath="+destPath);
			
			
//			strInterval=pro.getProperty(conf_prefix+"interval");	//完全备份的时间间隔

			sql = "Select Val From SYS_Setting Where Key='"+DirectorConstants.File_Backup_Interval+"'";
			rs = stmt.executeQuery(sql);
			if(rs.next()){
				strInterval= rs.getString("Val");
			} else {
				throw new Exception("数据库中没有完全备份间隔数据！");
			}
			log.debug ("user-strInterval="+strInterval);

			// 以下文件备份不需要，复制需要
//			
//			lastBackup =pro.getProperty(conf_prefix+"lastBackup");	//上次全备路径
//			destBackup =pro.getProperty(conf_prefix+"destBackup");	//本次路径
//			diskNeeded =pro.getProperty(conf_prefix+"diskNeeded");	//是否需要盘符
//			String strPos=pro.getProperty(conf_prefix+"beginPos");
			beginPos=0;
//			
//			
//			if(strPos!=null){
//				beginPos   =Integer.parseInt(strPos);	//生成目标路径开始位置
//			}
			
			//if(destPath==null||srcPath0==null||srcPath0.trim().equals("")){
			//	log.debug ("配置文件错误！");
			//	System.exit(0);
			//}
			
			//下面没有做转换异常的判断
			interval=Integer.parseInt(strInterval);
			
			String copyFrom="";	//"D:/test/";		//backup 源文件夹，必须要后面的/。
			String copyTo=destPath.trim();		//"F:/Woo_backup/";	//backup 目标文件夹
			
			
			//log.debug ("to"+copyTo);
			FilesBackupBean fb=new FilesBackupBean();
			//调用方法  //if(toDay.getDay()==1){
			fb.backupType=FilesBackupBean.FILEBACKUPTYPE_FULL;
			
			//下面是每个星期一次完全备份的代码
			/*
			if(toDay.getDay()!=1){
				......
			}*/
			//下面是自定义完全备份间隔的代码
			//如果配置信息没有指定上次全备份路径，循环查找上次全备份
			long lTime=  bakDay.getTime() ; //toDay.getTime() ;//+ ( new Float(Float.parseFloat(tjsd)*60*60) ).intValue() ;	
			long lIntval ;
			sdf.applyPattern("yyyy-MM-dd HH"); //
			String strDate=sdf.format(bakDay);
			
			long interHours=2;
			sql = "Select Val From SYS_Setting Where Key='"+DirectorConstants.File_Backup_Interv+"'";
			rs = stmt.executeQuery(sql);
			if(rs.next()){
				interHours= Integer.parseInt( rs.getString("Val") );
			}
			log.debug ("user-Interv each backup intervl is " + interHours + " hours, and full back is " + interval +" hours");

			Date pMonday= new java.util.Date();
			long tmpTimes = interval/interHours;
			if(lastBackup==null||lastBackup.trim().equals("")){
				for(long i=1;i<tmpTimes;i++){		// wzw on 2006-8-8 define i is long, not int.
					
					//lIntval = i*24*60*60*1000 ; 
					//log.info ( "long i="+i + "   inv="+ i*24*60*60*1000 + "  lIntval="+lIntval);
					//log.debug ( lTime - i*24*60*60*1000 );

					pMonday.setTime(lTime - i*interHours*60*60*1000 );	//i*24*60*60*1000
					sdf.applyPattern("yyyy-MM-dd HH");
					String strMonday=sdf.format(pMonday);				
					
					fb.lastBackup=copyTo+strMonday+"_C/";//+copyFrom.replace(":","");
					lastBackup=fb.lastBackup;
					log.debug ( fb.lastBackup );

					if(new File(fb.lastBackup).exists()){
						log.debug ("increase 9  ");
						fb.backupType=FilesBackupBean.FILEBACKUPTYPE_INCREASE;
						log.debug ("pday complete is "+strMonday);
						break;
					}
				}
			}else{
				fb.backupType=FilesBackupBean.FILEBACKUPTYPE_INCREASE;
			}	
			
	
			log.info ("bktype="+(fb.backupType==1?"完全备份":"增量备份"));			
			
			//备份目标文件夹
			if(destBackup==null||destBackup.trim().equals("")){
				if(fb.backupType==FilesBackupBean.FILEBACKUPTYPE_FULL){
					copyTo+=strDate+"_C/";//+copyFrom.replace(":","");
				}else{
					copyTo+=strDate+"_I/";//+copyFrom.replace(":","");
				}
			}else{
				copyTo=destBackup;
			}
			
			String thisCopyTo=null,thisLastBackup=null;

			List fromList = new ArrayList();
			if(fileUriList==null){
				sql = "Select Path From "+DirectorConstants.FMT_FileBackup+" Where LBBH='"+backupSort.trim()+"'  Order By Path ASC";
				rs = stmt.executeQuery(sql);
				while(rs.next()){
					copyFrom= rs.getString("Path");
					if(copyFrom==null||copyFrom.trim().equals("")){
						continue;
					} else {
						copyFrom = copyFrom.trim();
						fromList.add( copyFrom );
					}
				}
			}else{
				fromList = fileUriList ;
			}

			// 调用文件复制bean,并且附参数。
			FilesCopyBean fc = new FilesCopyBean();
			fc.setFilter();
			fc.executeCopy( fromList, copyTo, fb.lastBackup );
			
			log.info ("backup files success!");
			
		}catch(SQLException e){
			log.error ("Database Error: " +e.getMessage());
			//return ;
			throw e ;
		} catch(java.io.IOException e){
			log.error ("cann't load properties.properties file" +e.getMessage());
			//return ;
			throw new Exception( "cann't load properties.properties file" +e.getMessage() );
		} finally{
			//释放资源
			wzw.util.DbUtils.closeQuietly(conn, stmt, rs);
		}	

	}
	
	/**
     * <p>复制文件到指定的文件夹，采用字节流复制。</p>
     * @author WUZEWEN on 2005-10-17
     * @param copyFrom 原文件夹
     * @param copyTo 目标文件夹
     * @return 复制成功返回true，复制失败返回false。
     * @throws no exception
     */
	public boolean copyFolderAndFile(String copyFrom,String copyTo,String lastBackup){
		java.io.File fileFromFolder=new java.io.File(copyFrom);
		java.io.File fileToFolder=new java.io.File(copyTo);
		//java.io.File lastBackFolder=new java.io.File(lastBackup);	//is never read.
		
		File[] files=fileFromFolder.listFiles();
		//先创建对象(引用)
		String fileName="";
		File toFile=null;
		File lastFile=null;
		//FileInputStream fin=null;	//is never read.
		FileOutputStream fout=null;
		BufferedInputStream bufferIn=null;
		//BufferedOutputStream bufferOut=null;	//is never read.
		byte[] databytes=new byte[1024];
		int k;
		long lst;
		java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm");	//去掉 :ss
		

		//如果是完全备份而且目标文件夹不存在，创建
		if(this.backupType==FilesBackupBean.FILEBACKUPTYPE_FULL){		
			if(!fileToFolder.exists()){
				// fileToFolder.mkdir();
				createFolder(copyTo);	//多层的
				fileToFolder=new java.io.File(copyTo);
				fileToFolder.setLastModified(fileFromFolder.lastModified());//同步时间
			}
		}
		try{
			for(int i=0;i<files.length;i++){
				fileName=files[i].getName();	//初始化对象
				if(files[i].isFile()){
					toFile=new File(copyTo+fileName);
					lastFile=new File(lastBackup+fileName);
					
					//如果文件没有改变，退出
					//log.debug ("file= "+fileName+"\n"+toFile.lastModified()+"=="+files[i].lastModified()+"\n"+new Date(toFile.lastModified())+"\n"+new Date(files[i].lastModified()));
					//log.debug (sdf.format(new Date(toFile.lastModified())) +" "+ sdf.format(new Date(files[i].lastModified())));
					//log.debug (sdf.format(new Date(toFile.lastModified())).equals(sdf.format(new Date(files[i].lastModified()))));
					if(this.backupType==FilesBackupBean.FILEBACKUPTYPE_INCREASE){
						if(sdf.format(new Date(lastFile.lastModified())).compareTo(sdf.format(new Date(files[i].lastModified()))) >=0){
							//如果上次备份的文件大于等于现在的工作文件，不处理
							//log.debug ("file not modified!");
						}else{
							log.debug ("file modified and copy-["+sdf.format(new Date(files[i].lastModified()))+"|"
															+ (lastFile.exists()?sdf.format(new Date(lastFile.lastModified())):"no old file found")
															+"]: "+copyTo+fileName);
							

							//如果目标文件夹不存在，创建
							if(!fileToFolder.exists()){
								//fileToFolder.mkdir();
								createFolder(copyTo);	//多层的
								fileToFolder=new java.io.File(copyTo);
								fileToFolder.setLastModified(fileFromFolder.lastModified());//同步时间
							}							
							toFile.createNewFile();
							toFile.setLastModified(files[i].lastModified());
							bufferIn=new BufferedInputStream(
										new FileInputStream(files[i]));
							fout=new FileOutputStream(toFile);
							while((k=bufferIn.read(databytes))!=-1){
								//log.debug ("btyes="+databytes);
								fout.write(databytes,0,k);
								//databytes=new byte[1024];
							}
							bufferIn.close();
							fout.close();
							
							lst=files[i].lastModified();
							toFile.setLastModified(lst);		//因为被截断，不会精确到秒
							//return true;
						}
					}else{							
						//完全备份
						toFile.createNewFile();
						toFile.setLastModified(files[i].lastModified());
						bufferIn=new BufferedInputStream(
									new FileInputStream(files[i]));
						fout=new FileOutputStream(toFile);
						while((k=bufferIn.read(databytes))!=-1){
							fout.write(databytes,0,k);
							//databytes=new byte[1024];
						}
						bufferIn.close();
						fout.close();
						
						lst=files[i].lastModified();
						toFile.setLastModified(lst);		//因为被截断，不会精确到秒
					}
					
				}else if(files[i].isDirectory()){
					//log.debug ("file= "+fileName);
					//对于临时文件夹(名称以temp打头的)以及其子文件夹不备份。
					//if((!fileName.toLowerCase().equals("temp")) && (!fileName.toLowerCase().equals("temporary"))){
					if(!(fileName.toLowerCase().startsWith("temp"))){
						copyFolderAndFile(copyFrom+fileName+"/",copyTo+fileName+"/",lastBackup+fileName+"/");
					}else{
						//如果没有文件夹，创建文件夹，但是不复制文件
						if(!(new File(lastBackup+fileName+"/")).exists()){
							(new File(copyTo+fileName+"/")).mkdirs();
						}
					}
				}
			}
		}catch(Exception ex){
			log.debug ("ex="+ex);
		}
		return true;
	}
	
	/**
	 * <p>根据路径，创建目录</p>
     * @author WUZEWEN on 2005-10-17
     * @param path 要创建的文件夹的路径字符串，分割符为/
     * @return 如果路径存在或者创建成功，返回true，如果创建失败，返回false。
     * @throws no exception
     */
	public boolean createFolder(String path){
		//path like D:/a/b/c/d/e/
		log.debug ("create path="+path);
		if(path.endsWith("/")){
			path=path.substring(0,path.length()-1);
		}
		if(path.indexOf("/")>0){
			String parentPath = path.substring(0,path.lastIndexOf("/")+1);
			File folder=new File(parentPath);
			if(!folder.exists()){
				createFolder(parentPath);	//如果上级目录不存在，先创建
				//folder=new File(path);
				//folder.mkdirs();	//如果上级目录不存在，创建所有需要的，创建的文件夹不能像文件一样设置时间
			}
			folder=new File(path);
			folder.mkdir();
		}else{
			//到了盘符级了
			return true;
		}
		return true;
	}
	
	/**
	 * <p>将中文字符转换为 GB2312，解决中文乱码问题。</p>
     * @author WUZEWEN on 2005-10-17
     * @param s 要转换的字符串
     * @return 转换之后的字符串
     * @throws Exception java.io.UnsupportedEncodingException
     */
    public static  String toGB2312(String s) throws Exception {
        if (s == null || s.length() < 1)
            return  s;
        byte[] temp_b = s.getBytes("ISO-8859-1");
        String sTmpStr = new String(temp_b, "GB2312");
        return sTmpStr;

    }

	public static void executeBackup(List<String> fileUriList) throws Exception {
		executeBackup(null, null, fileUriList);
	}

}
